# -*- coding: utf-8 -*-
'''
Created on 25.04.2009

@author: renat
'''

import re

# activity by nodes
nodes = [[],[],[],[],[],[],[],[]]
# map to trace a single package
packages = {} 

aodv_packages = []
#packets stats 
results = {}



reTime = re.compile('-t (.*?) ')
reNode = re.compile('-Ni (.*?) ')
reType = re.compile('-It (.*?) ')
reLen = re.compile('-Il (.*?) ')
reId = re.compile('-Ii (.*?) ')
reLevel = re.compile('-Nl (.*?) ')
reDropReason = re.compile('-Nw (.*?) ')


#event class
class inf:
    def __init__(self,s):
        self.id = None
        self.evt_type = s[0]
        self.time = float(reTime.search(s).group(1))
        self.node = int(reNode.search(s).group(1))
        self.type = reType.search(s)
        if self.type : self.type = self.type.group(1)
        tmpLen = reLen.search(s)
        if tmpLen:
            self.len = int(tmpLen.group(1))
        else :
            self.len = 0  
        self.level = reLevel.search(s).group(1)
        self.reason = reDropReason.search(s).group(1)
        if self.evt_type == 'd' and self.reason == '---':
            self.reason = "n1:"+self.level
    def sent(self):
        return False
    def recieved(self):
        return False
        


class chain:
    def __init__(self, evt):
        self.events = [evt]
        
    def add(self,evt):
        self.events.append(evt)
        
    def started(self):
        '''
        @return: прошли 2 события: отправка и прием на 0 узле
        '''
        return len(self.events)>2
    
    def ping(self):
        '''
        @return:  время передачи одного пакета 
        '''
        return self.events[-1].time - self.events[0].time

     


class stat:
    def __init__(self, proc):
        self.send=0
        self.recv=0
        self.fwd=0
        self.drp=0
        self.p = proc
    def reset(self):
        self.send,self.recv,self.fwd,self.drp=0,0,0,0
    def r(self,len):
        self.recv+=len
    def s(self,len):
        self.send+=len
    def f(self,len):
        self.fwd+=len
    def d(self,len):
        self.drp+=len
    def printStat(self):
        return `self.send*8/(self.p.dct*1000)`+" "+`self.recv*8/(self.p.dct*1000)`+" "+`self.fwd*8/(self.p.dct*1000)`+" "+`self.drp*8/(self.p.dct*1000)`



class process:
    dct=1
    
    def __init__(self,nodenum):
        # time period for stats 
        self.dct = process.dct
        self.files = []
        self.stats = []
        self.ping=0
        self.rcvd=0
        self.drp=0
        self.gkey=''
        self.sent=0
        self.mode = "w"
        self.tmpev = {}
        self.ops = {"r":self.r, "s":self.s, "f":self.f, "d":self.d}
        self.pack_stats = {}
        self.last = 0
        self.nodenum = nodenum

    def open(self):
        self.time=self.dct
        self.overall = open("../data/overall",self.mode)
        for i in range(self.nodenum):  
            self.files.append(open("../data/"+`i`,self.mode))
            self.stats.append(stat(self))
        
    def parse(self,file):
        for s in file:
            self.work(s);  
        
            
         
    def flush(self):
        if self.gkey:
            skey = self.gkey
        else:
            skey = `self.time`
        self.overall.write(skey + " "+`self.sent/process.dct` + " "+`self.rcvd/process.dct` + " "+`self.ping_norm()`+"\n")
        for i in range(self.nodenum):
            file = self.files[i]
            st   = self.stats[i]
            file.write(`self.time`+ " "+st.printStat()+"\n")
            st.reset()
            
        self.rcvd=0
        self.drp=0
        self.ping=0

        self.sent=0
        
        self.time+=self.dct
        print self.time,"..."
        
    def ping_norm(self):
        if self.rcvd:
            return self.ping/self.rcvd
        else :
            return 0

    def close(self):
        if self.last < self.dct :
            self.dct = self.last
            self.flush();
        for file in self.files:
            file.close()
            print "closing", file
        self.overall.close()
        print "closing", self.overall


        
    def process(self, evt):
        '''
        Обработка события
        
        @type evt: inf()
        @param evt: [inf] event
        '''
        if evt.id:
            if evt.id in self.tmpev.keys() :
                self.tmpev[evt.id].add(evt)
            else :
                self.tmpev[evt.id]= chain(evt)
        
        self.ops[evt.evt_type](evt)
        
        self.last = evt.time
         
        if evt.time > self.time :
            self.flush()
            
        
        
        
        
    def r(self, evt):
        '''
        обработка приёма
        @type evt:inf() 
        @param  evt:
        '''
        if evt.id:
            c = self.tmpev[evt.id]
            if evt and evt.recieved() :
                self.ping+= c.ping()
                self.rcvd+=1
                del self.tmpev[evt.id]
        #if evt.level == 'AGT' :
        self.stats[evt.node].r(evt.len)
        if evt.len:
            reason = `evt.node`+" RCV "+ evt.level 
            if reason in self.pack_stats :
                self.pack_stats[reason]+=1
            else:
                self.pack_stats[reason]=1
            
    
    def f(self, evt):
        self.stats[evt.node].f(evt.len)
        if evt.len:
            reason = `evt.node`+" FWD " 
            if reason in self.pack_stats :
                self.pack_stats[reason]+=1
            else:
                self.pack_stats[reason]=1
 
        
    def s(self, evt):
#        if evt.level == 'AGT' :
        if evt.sent():
            self.sent+=1
        self.stats[evt.node].s(evt.len)
        if evt.len:
            reason = `evt.node`+" SNT " + evt.level 
            if reason in self.pack_stats :
                self.pack_stats[reason]+=1
            else:
                self.pack_stats[reason]=1
        

    def d(self, evt):
#        if evt.id in self.tmpev:
#            pass
#        else:
#            print "strange drop", evt.id 
        if evt.id :
            del self.tmpev[evt.id]
        self.stats[evt.node].d(evt.len)
        self.drp+=1
        if evt.len:
            reason = `evt.node`+" " + evt.reason 
            if reason in self.pack_stats :
                self.pack_stats[reason]+=1
            else:
                self.pack_stats[reason]=1


# actions on event
    def work(self,s):
        if  s[0] == 'M' :
            return
         
        i = inf(s)
     
    
        id = reId.search(s)
        
        if i.type == "AODV":
            aodv_packages.append(i)
            return 
        
        if id :
            i.id = int(id.group(1))
        self.process(i)

                
